﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ISRecord.Model;
using System.ComponentModel;
using ISRecord.View.Services;
using System.Windows.Data;
using System.Windows.Input;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.ObjectModel;
using ISRecord.View.Properties;
using ISRecord.View.Views;
using SysWindows =  System.Windows;


namespace ISRecord.View.ViewsModel
{
    public class AllOutboxesViewModel : WorkspaceViewModel
    {
        OutboxRepository repository;
        ICollectionView outboxes;
        DelegateCommand findCommand;
        DelegateCommand editCommand;
        DelegateCommand refreshCommand;
        public AllOutboxesViewModel()
        {
            Sender2006Entities context = new Sender2006Entities();
            repository = new OutboxRepository(context);
            base.DisplayName = Resources.AllOutboxesDispalyName;

        }
        void FillAll(IList<Outbox> list)
        {
            if (Outboxes != null) Outboxes.CurrentChanged -= Outboxes_CurrentChanged;
            Outboxes = CollectionViewSource.GetDefaultView(list);
            Outboxes.CurrentChanged += Outboxes_CurrentChanged;
        }

        void Outboxes_CurrentChanged(object sender, EventArgs e)
        {
            SelectedItem = Outboxes.CurrentItem as Outbox;
        }
        public Outbox SelectedItem { get; private set; }
        public ICollectionView Outboxes
        {
            get { return outboxes; }
            private set
            {
                outboxes = value;
                RaisePropertyChanged("Outboxes");
            }
        }
        #region Search Criteria Propertis

        string outbox;
        public string OutboxNo
        {
            get { return outbox; }
            set
            {
                if (value != outbox)
                {
                    outbox = value;
                    RaisePropertyChanged("OutboxNo");
                }
            }
        }
        string outboxDate;
        public string OutboxDate
        {
            get { return outboxDate; }
            set
            {
                if (value != outboxDate)
                {
                    outboxDate = value;
                    RaisePropertyChanged("OutboxDate");
                }
            }
        }
        string subject;
        public string Subject
        {
            get { return subject; }
            set
            {
                if (value != subject)
                {
                    subject = value;
                    RaisePropertyChanged("Subject");
                }
            }
        }
        string goingTo;
        public string GoingTo
        {
            get { return goingTo; }
            set
            {
                if (value != goingTo)
                {
                    goingTo = value;
                    RaisePropertyChanged("GoingTo");
                }
            }
        }
        #endregion

        #region "Commands"
        public ICommand FindCommand
        {
            get
            {
                if (findCommand == null)
                {
                    findCommand = new DelegateCommand(param => Find());
                }
                return findCommand;
            }
        }

        void Find()
        {
            try
            {
                Expression<Func<Outbox, bool>> criteria = BuildCriteria();

                if (criteria != null)
                {
                    IList<Outbox> list = repository.Query(criteria).ToList();
                    FillAll(list);
                }
                else
                {
                    IList<Outbox> list = repository.GetAll();
                    FillAll(list);
                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    Logger.Error(ex.InnerException.Message, "AllOutboxesViewMode", "Find");
                }
                else
                {
                    Logger.Error(ex.Message, "AllOutboxesViewModel", "Find");
                }
                Helper.ShowMessage(ex.Message, MessagePrompetType.ReportError);
            }
        }
        public ICommand EditCommand
        {
            get
            {
                if (editCommand == null)
                {
                    editCommand = new DelegateCommand(param => Edit());
                }
                return editCommand;
            }
        }
        void Edit()
        {



        }
        public ICommand RefreshCommand
        {
            get
            {
                if (refreshCommand == null)
                {
                    refreshCommand = new DelegateCommand(par => Refresh());
                }
                return refreshCommand;
            }
        }
        void Refresh()
        {
            repository.RefreshContext();
            Find();
        }
        private Expression<Func<Outbox, bool>> BuildCriteria()
        {
            MethodInfo stringNullOrEmpty = typeof(string).GetMethod("IsNullOrEmpty");
            MethodInfo contains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            MethodInfo compareTo = typeof(string).GetMethod("CompareTo", new[] { typeof(string) });
            ParameterExpression param = Expression.Parameter(typeof(Outbox), "outbox");
            Expression expr = null;

            Expression outboxNoProperty = Expression.PropertyOrField(param, "OutboxNo");
            Expression outboxDatePropery = Expression.PropertyOrField(param, "OutboxDate");
            Expression subjectProperty = Expression.PropertyOrField(param, "Subject");
            Expression goingToProperty = Expression.PropertyOrField(param, "GoingTo");

            Expression outboxValue = ConstantExpression.Constant(this.OutboxNo, typeof(string));
            Expression outboxDateValue = ConstantExpression.Constant(this.OutboxDate, typeof(string));
            Expression subjectValue = ConstantExpression.Constant(this.Subject, typeof(string));
            Expression goingToValue = ConstantExpression.Constant(this.GoingTo, typeof(string));

            MethodCallExpression testOutboxIdhasValue = Expression.Call(null, stringNullOrEmpty, new[] { outboxValue });
            Expression testOutboxDateHasValue = Expression.Call(null, stringNullOrEmpty, new[] { outboxDateValue });
            Expression testSubjectHasValue = Expression.Call(null, stringNullOrEmpty, new[] { subjectValue });
            Expression testGoingToHasValue = Expression.Call(null, stringNullOrEmpty, new[] { goingToValue });
            bool expressionAssigned = false;
            if (!string.IsNullOrEmpty(OutboxNo))
            {
                Expression temp = Expression.Equal(outboxNoProperty, outboxValue);
                expr = temp;
                if (!expressionAssigned) expressionAssigned = true;
            }
            if (!string.IsNullOrEmpty(OutboxDate))
            {
                if (!expressionAssigned)
                {
                    //Note: "'CompareTo' Method of type string is equivalent to > < operators in SQL refer to doc for more."
                    ConstantExpression constant = Expression.Constant(0);
                    Expression temp = Expression.GreaterThanOrEqual(
                        Expression.Call(outboxDatePropery, compareTo, outboxDateValue), constant);
                    expr = temp;
                    expressionAssigned = true;
                }
                else
                {
                    ConstantExpression constant = Expression.Constant(0);
                    Expression temp = Expression.GreaterThanOrEqual(
                        Expression.Call(outboxDatePropery, compareTo, outboxDateValue), constant);

                    expr = Expression.AndAlso(expr, temp);
                }
            }
            if (!string.IsNullOrEmpty(Subject))
            {

                if (!expressionAssigned)
                {

                    Expression temp = Expression.Call(subjectProperty, contains, subjectValue);
                    expr = temp;
                    expressionAssigned = true;
                }
                else
                {
                    Expression temp = Expression.Call(subjectProperty, contains, subjectValue);
                    expr = Expression.AndAlso(expr, temp);
                }
            }
            if (!string.IsNullOrEmpty(GoingTo))
            {
                if (!expressionAssigned)
                {
                    Expression temp = Expression.Call(goingToProperty, contains, goingToValue);
                    expr = temp;
                    expressionAssigned = true;
                }
                else
                {
                    Expression temp = Expression.Call(goingToProperty, contains, goingToValue);
                    expr = Expression.AndAlso(expr, temp);
                }
            }
            Expression<Func<Outbox, bool>> criteria = null;
            if (expr != null)
            {
                criteria = Expression.Lambda<Func<Outbox, bool>>(expr, param);
            }
            return criteria;
        }
        #endregion
        public override void Cleanup()
        {
            repository.Dispose();
            if (Outboxes != null)
            {
                Outboxes.CurrentChanged -= Outboxes_CurrentChanged;
            }
            base.Cleanup();
        }



       
    }
}
